home *** CD-ROM | disk | FTP | other *** search
/ Language/OS - Multiplatform Resource Library / LANGUAGE OS.iso / scheme / pcscheme / geneva / sources.exe / DOC / INLINE.DOC < prev    next >
Encoding:
Text File  |  1992-12-07  |  8.6 KB  |  246 lines

  1. -----------------------------INLINE DOCUMENTATION-------------------------------
  2.     Interfacing Scheme to assembly code, by Larry Bartholdi
  3. --------------------------------------------------------------------------------
  4.  
  5.     Typically, scheme users (as all high-level language users) are allowed
  6. little if no knowledge of the whats and the hows of their system. The reason
  7. is somewhat ideological (opposing 'hackers' to 'theoreticians'), but is also
  8. a safety concern. Using a lower level allows greater freedom but meaner bugs,
  9. and the software engineer should always consider the high-level approach first.
  10.  
  11. Nevertheless, PC Scheme/Geneva allows full access to lower levels through
  12. a special list structure, that can be executed. The lists that can be executed
  13. are of two kinds: PCS-CODE-BLOCKS (PCB) and PCS-INLINE-BLOCKS (PIB).
  14.  
  15. A PCB is defined thus: (list 'PCS-CODE-BLOCK #symbols #codebytes
  16.             (list <symbol> ...) (list <codebyte> ...))
  17.  
  18. It is supposed to be executed by the PCS virtual machine (VM).
  19. The symbols are accessible from the code through the mov_constant instruction,
  20. and the code bytes are of course the instructions to be executed.
  21. If this sounds too abstract, try ``(compile '(+ a 1))'', and you will see:
  22.  
  23.     (PCS-CODE-BLOCK 1 10 (A) (2 4 1 6 8 0 80 4 8 59))
  24.  
  25. This is a code block containing 1 symbol (A), and 10 code bytes, reading
  26.  
  27.     2 4 1        : load-immediate 1
  28.     6 8 0        : lookup-value of A
  29.     80 4 8        : add up the values
  30.     59        : return
  31.  
  32. The complete instruction set can be found in sources.asm\assembly.ash.
  33. Generally speaking, these instructions are executed by a 64-register
  34. tagged virtual machine. Scheme code is translated in a highly optimised
  35. VM code block, so little can be gained by hand-coding inner loops.
  36. If you don't trust me, give a look to recur.s. It contains a good scheme
  37. routine and an optimal VM machine. The performances match to about 10%,
  38. while the development times differed by a factor of 10 !
  39. Note also that VM instructions might differ from one version of PCS to
  40. another, so you might have to rewrite your code if you use PCB directly...
  41.  
  42. Of greater interest are PIBs. They are defined as:
  43.     (list 'PCS-INLINE-BLOCK #bytes (list <byte> ...))
  44.  
  45. The byte list corresponds to 8086 instructions. As a PIB is executed,
  46. control is passed to the first byte of the list. The assembly subtask
  47. must then return with a far return (#hCB). All registers may be trashed except
  48. SS and SP (and of course CS and IP!).
  49.  
  50. A trivial example is then: (try it!)
  51.  
  52.     (%EXECUTE '(PCS-INLINE-BLOCK 1 (#hCB))) ---> undefined value
  53.  
  54. What is now needed is parameter passing. This is provided by a special
  55. construct,
  56.     (inline-lambda (args ...) P[IC]B).
  57.  
  58. Inline-lambda takes an argument list (or a number of arguments) and executes
  59. the block it was passed with the arguments spreaded over VM registers R1-R61.
  60. The assembly or VM code can then access the registers, modify them, etc.
  61. and return a value in register R1.
  62.  
  63. Again a simple example:
  64.  
  65.     ((inline-lambda (n) '(pcs-inline-block 1 (#hCB))) 1234)
  66.  
  67. would return 1234, because the value passed in R1 (1234) is not changed.
  68.  
  69. To code less trivial programs, some definitions, macros and aliases are
  70. needed. They can be found in sources.asm\inline.ash.
  71. inline.ash defines equates for VM registers R0-R63
  72. (R0 is nil, and R63 is reserved), structures to access these registers,
  73. and helper functions.
  74.  
  75. A VM register is defined as a base and a displacement into VM's paginated
  76. memory. The bases are 8-bit values used as indexes in a segment table. 
  77. To examine the object pointed to by a register, one would typically use:
  78.  
  79.     mov    bx, [reg1.page]        ; get the register's page
  80.     call    ldpage C, bx        ; get the corresponding segment in bx
  81.     mov    es, ax
  82.     mov    bx, [reg1.disp]        ; get the displacement part of the reg.
  83.  
  84. and the data can be found at [es:bx].
  85.  
  86. The objects can be of various types: fake objects like short integers
  87. (signed 16-bit) which are just their displacement value, or true
  88. objects composed of a tag (1 byte), a length (2 bytes) and some data.
  89. The length includes the tag and the length bytes. Many objects contain
  90. pointers, which are just another representation for a register, except
  91. the register is 32-bit with disp first, while the pointer is 24-bit
  92. with page first.
  93. The tag-length-data motto is violated by two objects: lists and floating-point
  94. numbers, whose size is fixed. A pair is just two pointers, while a flonum
  95. is a tag followed by the 64-bit data. My...
  96.  
  97. You can recognize or allocate a new Scheme object specifying its type (tag):
  98.     LISTTYPE    =    0
  99.     FIXTYPE        =    2
  100.     FLOTYPE        =    4
  101.     BIGTYPE        =    6
  102.     SYMBTYPE    =    8
  103.     STRTYPE        =    10
  104.     VECTTYPE    =    12
  105.     CONTTYPE    =    14
  106.     CLOSTYPE    =    16
  107.     FREETYPE    =    18
  108.     CODETYPE    =    20
  109.     I86TYPE        =    22
  110.     PORTTYPE    =    24
  111.     CHARTYPE    =    26
  112.     ENVTYPE        =    28
  113. Any other value would cause unpredictable result... See INLINE.ASH for more
  114. details on internal structure of VM objects.
  115.  
  116. Reg0-reg63 are aliases; an assembly code block is given control with DS:SI
  117. pointing to register R0, so SI must be preserved as long as the
  118. routine wants to access registers. DI is also used and points to a dispatch
  119. table allowing dynamic linking to the most important PCS routines,
  120. here documented by example:
  121.  
  122.     call    ldpage C, PAGE
  123.             returns a segment descriptor in ax
  124.  
  125.     call    alloc_big_block C, REGPTR, TYPE, SIZE
  126.             allocates a big memory block (> 1/128 of total memory)
  127.             REGPTR is a register's address that will point to the
  128.             new object.
  129.     call    alloc_block C, REGPTR, TYPE, SIZE
  130.             allocates a variable-length object.
  131.     call    alloc_flonum C, REGPTR, FLOVALUE
  132.             allocates and stores a 64-bit FP value
  133.     call    alloc_int C, REGPTR, BIGNUM_buffer
  134.             ditto - where a BIGNUM buffer is a size (1 word)
  135.             in words, a sign (1 byte) 0 or 1, and the data, LSB first.
  136.     call    alloc_list_cell C, REGPTR
  137.             finds storage for a pair
  138.     call    alloc_string C, STRING
  139.             ditto - the string is null-terminated
  140.  
  141.     call    cons C, REGPTR1, REGPTR2, REGPTR3
  142.             allocates a pair, sets its car to REGPTR2 and its cdr to
  143.             REGPTR3, and makes REGPTR1 point to the pair.
  144.  
  145.     call    free C, memory block
  146.             the standard C function
  147.  
  148.     call    getch C
  149.             guess what
  150.     call    get_max_cols C
  151.             returns the screen's width
  152.     call    get_max_rows C
  153.             returns the screen's depth
  154.  
  155.     call    int2long C, REGPTR
  156.             reads a number from the register REGPTR and returns
  157.             it in DX:AX (32-bit signed). No checks are done.
  158.  
  159.     call    is_graph_mode C
  160.             returns 1 if graphics mode, 0 if alphanumeric
  161.  
  162.     call    long2int C, REGPTR, 32VALUE
  163.             sets register REGPTR to the 32-bit signed value 32VALUE
  164.  
  165.     call    malloc C, SIZE
  166.             the standard C function
  167.     call    nosound C
  168.             turns off the speaker
  169.     call    sound C, FREQUENCY
  170.             turns on the speaker
  171.     call    zcuroff C
  172.             turns off the cursor
  173.     call    zcuron C
  174.             turns on the cursor
  175.     call    zprintf C, FORMAT, ...
  176.             like C's printf
  177.     call    zputc C, CHAR
  178.             write a character to the screen
  179.     call    zscroll C, LINE, COL, NLINES, NCOLS, ATTRIBUTE
  180.             scrolls the screen area up 1 line
  181.     call    zscroll_d C, (ditto)
  182.             scrolls the screen area down 1 line
  183.  
  184. Among the tricks to know is that an assembly block may be placed at anytime
  185. in memory, so all local variables must be accessed pc-relative, with the
  186. code:
  187.  
  188.     call    $+3
  189.     pop    bp
  190.     sub    bp, $-1
  191.     mov    ax, [bp+mydata]
  192. ...
  193. mydata    dw    ?
  194.  
  195. An example of this is given in inline\snow.asm.
  196.  
  197. Besides providing useful equates, inline.ash defines two macros,
  198.  
  199.     startinline    name, argcount
  200. and
  201.     endinline
  202.  
  203. These construction blocks delimit an assembly subroutine.
  204. The trivial example would be coded:
  205. ;---------------------------------------------- start of TRIVIAL.ASM
  206. IDEAL
  207. INCLUDE "inline.ash"
  208. StartInline    TRIVIAL, -1    ; -1 means any argument count (mu-lambda)
  209.     ret
  210. EndInline
  211. END
  212. ;---------------------------------------------- end of TRIVIAL.ASM
  213. and assembled with
  214.     TASM    trivial
  215.     TLINK /t trivial, trivial.bin
  216. now type PCS
  217.     (load "trivial.bin")
  218.     (trivial 1 2 3)
  219.     ----> (1 2 3)
  220.     (exit)
  221.  
  222.  
  223. You'll find some other examples in the inline\ subdirectory.
  224.  
  225. Note how to share tasks between Scheme and assembly code in 
  226. PEEK.ASM and PEEK.S : Typically, type checking, link to the debugger 
  227. and user interface should ALWAYS be written in pure Scheme.
  228. You should only use assembly code to do things you wouldn't be able
  229. to do in scheme (in our example, direct memory and port access).
  230. The compiled version, PEEK.BIN and PEEK.FSL, is located in PCS
  231. system directory but since they make an attempt against PCS decency,
  232. they are not spontaneously loaded; use (load "peek.fsl") if needed.
  233.  
  234.  
  235.  
  236. Please send any comments to schemege@uni2a.unige.ch,
  237. and, most of all, good luck !
  238.  
  239. 20 nov 1992 (lb)
  240.     
  241.  
  242.     
  243.  
  244. (*) Borland products (TASM, ...) are trademarks of Borland International Inc.
  245.     
  246.